<template>
  <div>
    <video id="localVideo" autoplay muted></video>
    <video id="remoteVideo" autoplay></video>
    <input type="text" v-model="roomId" placeholder="请输入房间ID" />
    <button @click="joinRoom">加入房间</button>
    <button @click="leaveRoom">离开房间</button>
  </div>
</template>

<script>
// 引入 adapter-latest.js 确保 WebRTC 兼容性
import '@/assets/adapter-latest.js';

export default {
  name: 'WebRTCChat',
  data() {
    return {
      localUserId: Math.random().toString(36).substr(2), // 本地用户ID
      remoteUserId: -1, // 对端用户ID
      roomId: '',
      localStream: null,
      remoteStream: null,
      pc: null,
      signaling: null,
    };
  },
  methods: {
    // 加入房间
    joinRoom() {
      if (!this.roomId) {
        alert("请输入房间ID");
        return;
      }
      console.log("加入房间: ", this.roomId);
      this.initLocalStream();
    },

    // 离开房间
    leaveRoom() {
      console.log("离开房间");
      this.doLeave();
    },

    // 初始化本地流
    initLocalStream() {
      navigator.mediaDevices
        .getUserMedia({ audio: true, video: true })
        .then(this.openLocalStream)
        .catch((e) => alert("getUserMedia() error: " + e.name));
    },

    // 打开本地流
    openLocalStream(stream) {
      console.log("打开本地流");
      this.localStream = stream;
      document.getElementById("localVideo").srcObject = stream;
      this.doJoin(this.roomId);
    },

    // 发送加入房间请求
    doJoin(roomId) {
      const jsonMsg = { cmd: "join", roomId, uid: this.localUserId };
      this.sendMessage(jsonMsg);
    },

    // 发送离开房间请求
    doLeave() {
      if (this.localStream) {
        this.localStream.getTracks().forEach((track) => track.stop());
      }
      if (this.pc) {
        this.pc.close();
      }
      this.localStream = null;
      this.remoteStream = null;
      this.pc = null;
      document.getElementById("localVideo").srcObject = null;
      document.getElementById("remoteVideo").srcObject = null;

      const jsonMsg = { cmd: "leave", roomId: this.roomId, uid: this.localUserId };
      this.sendMessage(jsonMsg);
    },

    // 发送消息
    sendMessage(message) {
      if (this.signaling && this.signaling.readyState === WebSocket.OPEN) {
        this.signaling.send(JSON.stringify(message));
      }
    },

    // 创建 WebSocket 连接
    createWebSocket() {
      this.signaling = new WebSocket("ws://192.168.130.146:10000"); // 替换为你的 WebSocket 服务器地址
      this.signaling.onopen = this.onOpen;
      this.signaling.onmessage = this.onMessage;
      this.signaling.onerror = this.onError;
      this.signaling.onclose = this.onClose;
    },

    // WebSocket 事件处理
    onOpen() {
      console.log("WebSocket 已打开");
    },
    onMessage(event) {
      console.log("WebSocket 消息: ", event.data);
      const jsonMsg = JSON.parse(event.data);
      switch (jsonMsg.cmd) {
        case "new-peer":
          this.handleRemoteNewPeer(jsonMsg);
          break;
        case "resp-join":
          this.handleResponseJoin(jsonMsg);
          break;
        case "peer-leave":
          this.handleRemotePeerLeave(jsonMsg);
          break;
        case "offer":
          this.handleRemoteOffer(jsonMsg);
          break;
        case "answer":
          this.handleRemoteAnswer(jsonMsg);
          break;
        case "candidate":
          this.handleRemoteCandidate(jsonMsg);
          break;
      }
    },
    onError(event) {
      console.log("WebSocket 错误: ", event);
    },
    onClose(event) {
      console.log("WebSocket 关闭: ", event.code);
    },

    // WebRTC 相关方法
    createPeerConnection() {
      const defaultConfiguration = {
        iceServers: [
          {
            urls: ["turn:192.168.130.146:3478?transport=udp", "turn:192.168.130.146:3478?transport=tcp"],
            username: "zwb",
            credential: "zwbsnd",
          },
          { urls: ["stun:192.168.130.146:3478"] },
        ],
      };
      this.pc = new RTCPeerConnection(defaultConfiguration);
      this.pc.onicecandidate = this.handleIceCandidate;
      this.pc.ontrack = this.handleRemoteStreamAdd;
      this.localStream.getTracks().forEach((track) => this.pc.addTrack(track, this.localStream));
    },

    handleIceCandidate(event) {
      if (event.candidate) {
        const candidateJson = {
          label: event.candidate.sdpMLineIndex,
          id: event.candidate.sdpMid,
          candidate: event.candidate.candidate,
        };
        const jsonMsg = {
          cmd: "candidate",
          roomId: this.roomId,
          uid: this.localUserId,
          remoteUid: this.remoteUserId,
          msg: JSON.stringify(candidateJson),
        };
        this.sendMessage(jsonMsg);
      }
    },

    handleRemoteStreamAdd(event) {
      this.remoteStream = event.streams[0];
      document.getElementById("remoteVideo").srcObject = this.remoteStream;
    },

    doOffer() {
      if (!this.pc) this.createPeerConnection();
      this.pc.createOffer()
        .then((session) => this.createOfferAndSendMessage(session))
        .catch((error) => console.error("createOffer failed: ", error));
    },

    createOfferAndSendMessage(session) {
      this.pc.setLocalDescription(session).then(() => {
        const jsonMsg = {
          cmd: "offer",
          roomId: this.roomId,
          uid: this.localUserId,
          remoteUid: this.remoteUserId,
          msg: JSON.stringify(session),
        };
        this.sendMessage(jsonMsg);
      });
    },

    doAnswer() {
      this.pc.createAnswer()
        .then((session) => this.createAnswerAndSendMessage(session))
        .catch((error) => console.error("createAnswer failed: ", error));
    },

    createAnswerAndSendMessage(session) {
      this.pc.setLocalDescription(session).then(() => {
        const jsonMsg = {
          cmd: "answer",
          roomId: this.roomId,
          uid: this.localUserId,
          remoteUid: this.remoteUserId,
          msg: JSON.stringify(session),
        };
        this.sendMessage(jsonMsg);
      });
    },

    handleRemoteNewPeer(message) {
      this.remoteUserId = message.remoteUid;
      this.doOffer();
    },

    handleResponseJoin(message) {
      this.remoteUserId = message.remoteUid;
    },

    handleRemotePeerLeave() {
      if (this.pc) {
        this.pc.close();
        this.pc = null;
      }
      document.getElementById("remoteVideo").srcObject = null;
    },

    handleRemoteOffer(message) {
      if (!this.pc) this.createPeerConnection();
      const desc = JSON.parse(message.msg);
      this.pc.setRemoteDescription(desc).then(() => this.doAnswer());
    },

    handleRemoteAnswer(message) {
      const desc = JSON.parse(message.msg);
      this.pc.setRemoteDescription(desc);
    },

    handleRemoteCandidate(message) {
      const jsonMsg = JSON.parse(message.msg);
      const candidate = new RTCIceCandidate({
        sdpMLineIndex: jsonMsg.label,
        sdpMid: jsonMsg.id,
        candidate: jsonMsg.candidate,
      });
      this.pc.addIceCandidate(candidate).catch((e) => console.error("addIceCandidate failed: ", e));
    },
  },
  mounted() {
    this.createWebSocket();
  },
  beforeDestroy() {
    if (this.signaling) this.signaling.close();
    this.doLeave();
  },
};
</script>

<style scoped>
#localVideo,
#remoteVideo {
  width: 100%;
  max-width: 400px;
  height: auto;
  border: 1px solid #ddd;
}
button {
  margin: 10px;
  padding: 8px 16px;
}
</style>